package com.bfl.sa.common.mybatis.entity;

import com.bfl.sa.common.entity.search.Searchable;
import com.bfl.sa.common.entity.search.filter.AndCondition;
import com.bfl.sa.common.entity.search.filter.Condition;
import com.bfl.sa.common.entity.search.filter.OrCondition;
import com.bfl.sa.common.entity.search.filter.SearchFilter;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.util.*;

public class Query extends HashMap<String, Object> {

    private final static Set<String> booleanField = new HashSet<>();

    static {
        booleanField.add("show");
        booleanField.add("deleted");
    }

    public Query() {}

    public static Query newQuery() {
        return new Query();
    }

    public static Query newQuery(String key, Object value) {
        Query query = newQuery();
        query.put(key, value);

        return query;
    }

    public static Query newQuery(Pageable pageable) {
        Query query = newQuery();
        if (pageable != null) {
            Map<String, Object> pageParam = new HashMap<>();
            pageParam.put("num", pageable.getPageNumber());
            pageParam.put("size", pageable.getPageSize());
            query.put("page.num", pageable.getPageNumber());
            query.put("page.size", pageable.getPageSize());
            query.put("page", pageParam);
        }
        return query;
    }

    public static Query newQuery(Searchable searchable) {
        Query query = newQuery();

        if (searchable != null) {
            Pageable page = searchable.getPage();
            if (page != null) {
                Map<String, Object> pageParam = new HashMap<>();
                pageParam.put("num", page.getPageNumber());
                pageParam.put("size", page.getPageSize());
                query.put("page.num", page.getPageNumber());
                query.put("page.size", page.getPageSize());
                query.put("page", pageParam);
            }

            Sort sort = searchable.getSort();
            if (sort != null) {
                Map<String, Object> sortParam = new HashMap<>();
                sort.forEach(s -> {
                    sortParam.put("field", s.getProperty());
                    sortParam.put("order", s.getDirection());
                });
                query.put("sort", sortParam);
            }

            if (searchable.hasSearchFilter()) {
                Collection<SearchFilter> searchFilters = searchable.getSearchFilters();
                searchFilters.forEach(searchFilter -> convertSearchValueToMap(query, searchFilter));
            }
        }

        return query;
    }

    public Query eq(String key, Object value) {
        this.put(key, value);
        return this;
    }

    /**
     * 封装查询Map
     * TODO or、and条件、参数值类型转换为对象属性值类型
     */
    private static void convertSearchValueToMap(Map<String, Object> params, SearchFilter searchFilter) {

        if (searchFilter instanceof Condition) {
            Condition condition = (Condition) searchFilter;
            String key = condition.getEntityProperty();
            Object value = condition.getValue();

            if (booleanField.contains(key)) {
                if ("true".equalsIgnoreCase(String.valueOf(value))) {
                    value = true;
                }
                if ("false".equalsIgnoreCase(String.valueOf(value))) {
                    value = false;
                }
            }

            params.put(key, value);
        }

        else if (searchFilter instanceof OrCondition) {
            for (SearchFilter orFilter : ((OrCondition) searchFilter).getOrFilters()) {
                convertSearchValueToMap(params, orFilter);
            }
        }

        else if (searchFilter instanceof AndCondition) {
            for (SearchFilter andFilter : ((AndCondition) searchFilter).getAndFilters()) {
                convertSearchValueToMap(params, andFilter);
            }
        }
    }

}
